home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / icon tools / opticon-1.8 / opticon.c < prev    next >
C/C++ Source or Header  |  1996-04-07  |  19KB  |  633 lines

  1. /*
  2.  *  OPTICON.C
  3.  */
  4.  
  5. #define VERSION "1.6"
  6. static char versiontag[] = "$VER: $Id: opticon.c,v 1.8 1994/07/17 22:41:11 tf Exp $";
  7.  
  8. /****** OptIcon ******************************************
  9. *
  10. *   NAME
  11. *    OptIcon -- Optimize icon images for size and speed (V36)
  12. *
  13. *   SYNOPSIS
  14. *    OptIcon NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,CRITICAL/S,VERBOSE/S
  15. *
  16. *   FUNCTION
  17. *    OptIcon reads in given ".info" files and scans the icon image
  18. *    in order to optimize the PlanePick and PlaneOnOff fields in the
  19. *    icon Image structure.  This is a space-saving mechanism for image
  20. *    data.
  21. *    Rather than defining the image data for every plane of the RastPort,
  22. *    you need define data only for the planes that are not entirely zero
  23. *    or one.  As you define your Imagery, you will often find that most
  24. *    of the planes ARE just as color selectors.  For instance, if you're
  25. *    designing a two-color icon to use colors one and three, and the icon
  26. *    will reside in a five-plane display, bit plane zero of your
  27. *    imagery would be all ones, bit plane one would have data that
  28. *    describes the imagery, and bit planes two through four would be
  29. *    all zeroes.  Using these flags avoids wasting all that memory in
  30. *    this way:  first, you specify which planes you want your data to
  31. *    appear in using the PlanePick variable.  For each bit set in the
  32. *    variable, the next "plane" of your image data is blitted to the
  33. *    display.  For each bit clear in this variable, the corresponding bit
  34. *    in PlaneOnOff is examined.  If that bit is clear, a "plane" of zeroes
  35. *    will be used.  If the bit is set, ones will go out instead.
  36. *    Note that if you want an Image that is only a filled rectangle, you
  37. *    can get this by setting PlanePick to zero (pick no planes of data)
  38. *    and set PlaneOnOff to describe the pen color of the rectangle.
  39. *
  40. *   INPUTS
  41. *    NAME          - name of the icon image file.  A trailing ".info"
  42. *            is optional but not required.
  43. *    DEPTH         - maximum number of bitplanes to be saved.
  44. *    VERBOSE       - display input and output information for each icon.
  45. *
  46. *   EXAMPLE
  47. *    ;Remove all but the first 3 planes of the icon image for the
  48. *    ;disk in drive DF0: but don't add any planes
  49. *    opticon df0:disk planes=3 noexpand
  50. *
  51. *   NOTES
  52. *    Since the IconEdit from Commodore will always save 8 bitplane icons
  53. *    the above example might be of great use to you.  (Note that 3 plane
  54. *    images are not only smaller but also faster!)
  55. *    Coming with OptIcon is the script PatchIcons which will recursively
  56. *    descend all subdirectories of a given path deleting all but the first
  57. *    3 planes of all icon images in that path.
  58. *
  59. *    OptIcon now also allows you to expand your 8 or more color icons
  60. *    for the use on a 16 or more color Workbench.  This is important due
  61. *    to the new color system under OS3.x which always shifts the second
  62. *    four colors to the end of the system palette.  Therefore you might
  63. *    want to adapt an icon's color depth to the actual screenmode it is
  64. *    used on.
  65. *
  66. *   EXAMPLE
  67. *    ;Remap the last 4 of at least 8 colors of the RAM DISK icon
  68. *    ;to the last 4 colors in a 16 or more colors Workbench palette
  69. *    opticon ram:disk planes=4
  70. *
  71. *   BUGS
  72. *    Commodore's PutDiskObject() currently [icon.library 40.1 (15.2.93)]
  73. *    re-expands icon images using the PlanePick/PlaneOnOff mechanism and
  74. *    in fact PutDiskObject() has quite a lot of problems doing so!
  75. *    For this reason OptIcon will perform the PlanePick/PlaneOnOff
  76. *    optimization only if the keyword CRITICAL is given in the command
  77. *    line.
  78. *
  79. *   DISCLAIMER
  80. *    This file is part of the Icon2C and OptIcon distribution.
  81. *
  82. *    Icon2C and OptIcon are free software; you can redistribute them
  83. *    and/or modify them under the terms of the GNU General Public License
  84. *    as published by the Free Software Foundation; either version 1 of
  85. *    the License, or (at your option) any later version.
  86. *
  87. *    Icon2C and Opticon are distributed in the hope that they will be
  88. *    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  89. *    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  90. *    GNU General Public License for more details.
  91. *
  92. *    You should have received a copy of the GNU General Public License
  93. *    along with these programs; see the file COPYING.  If not, write to
  94. *    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  95. *
  96. *   COPYRIGHT
  97. *    Icon2C and OptIcon are Copyright (C)1994 by Tobias Ferber.
  98. *    You can reach me via E-mail: ukjg@rz.uni-karlsruhe.de
  99. *
  100. *   SEE ALSO
  101. *    PatchIcons, Icon2C
  102. *
  103. ******************************************************************************
  104. *
  105. *    Compile w/ -DDEBUG to output more information at runtime
  106. */
  107.  
  108. #include <ctype.h>
  109. #include <stdlib.h>
  110. #include <string.h>
  111. #include <stdio.h>
  112.  
  113. #include <exec/types.h>
  114. #include <exec/memory.h>
  115.  
  116. #include <dos/dos.h>
  117. #include <dos/rdargs.h>
  118.  
  119. #include <intuition/intuition.h>
  120. #include <intuition/intuitionbase.h>
  121.  
  122. #include <workbench/workbench.h>
  123. #include <workbench/startup.h>
  124. #include <workbench/icon.h>
  125.  
  126. #include "memfn.h"
  127.  
  128. #ifdef __GNUC__
  129. /* suggest parentheses around assignment used as truth value */
  130. #define if(assignment) if( (assignment) )
  131. #endif /* __GNUC__ */
  132.  
  133. extern struct Library *OpenLibrary(STRPTR, ULONG);
  134. extern void CloseLibrary(struct Library *);
  135. extern void CopyMem(APTR, APTR, ULONG);
  136. extern void *AllocMem(ULONG, ULONG);
  137. extern void FreeMem(void *, ULONG);
  138. extern ULONG TypeOfMem(void *);
  139. extern struct RDArgs *ReadArgs(STRPTR, LONG *, struct RDArgs *);
  140. extern LONG IoErr(void);
  141. extern BOOL PrintFault(LONG, STRPTR);
  142. extern void FreeArgs(struct RDArgs *);
  143. extern struct DiskObject *GetDiskObject(char *);
  144. extern BOOL PutDiskObject(char *, struct DiskObject *);
  145. extern void FreeDiskObject(struct DiskObject *);
  146.  
  147. struct IconBase *IconBase;
  148.  
  149. void display_version_information(void)
  150. {
  151.   static char license[]=
  152.     "OptIcon is free software; you can redistribute it and/or modify\n"
  153.     "it under the terms of the GNU General Public License as published\n"
  154.     "by the Free Software Foundation; either version 1 of the License,\n"
  155.     "or (at your option) any later version.\n"
  156.     "\n"
  157.     "OptIcon is distributed in the hope that it will be useful,\n"
  158.     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  159.     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
  160.     "GNU General Public License for more details.\n"
  161.     "\n"
  162.     "You should have received a copy of the GNU General Public License\n"
  163.     "along with OptIcon; see the file COPYING.  If not, write to the\n"
  164.     "Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
  165.     ;
  166.  
  167.   puts("\nOptIcon Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
  168.        "(c)Copyright 1994 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de\n");
  169.  
  170.   puts(license);
  171. }
  172.  
  173.  
  174. struct Image *free_image(struct Image *i)
  175. {
  176.   if(i)
  177.   {
  178.     long size= i->Depth * i->Height * ((i->Width + 15) / 16) * sizeof(UWORD);
  179.  
  180.     if(i->ImageData && size > 0)
  181.       FreeMem( i->ImageData, size );
  182.  
  183.     FreeMem( i, sizeof(struct Image) );
  184.   }
  185.  
  186.   return (struct Image *)0L;
  187. }
  188.  
  189. /* command line options */
  190. #define OPT_NOEXPAND  (1<<0)
  191. #define OPT_CRITICAL  (1<<1)
  192. #define OPT_VERBOSE   (1<<2)
  193. #define OPT_REMAPV37  (1<<3)
  194.  
  195. struct Image *optimize_image(struct Image *i, WORD planes, int optimode)
  196. {
  197.   UWORD p16= i->Height * ((i->Width + 15) / 16); /* #of words per plane */
  198.   UWORD *idata= i->ImageData;
  199.   WORD d, dmax, D, P;
  200.   UBYTE pp= 0;    /* plane pick */
  201.   UBYTE p10= 0;   /* plane on/off */
  202.  
  203.   struct Image *o= i;  /* optimized image */
  204.  
  205.   /* prevent silly args from being harmful */
  206.  
  207.   if(!i)
  208.     return i;
  209.  
  210.   if(planes > 8)
  211.     planes= 8;
  212.  
  213.   if(optimode & OPT_VERBOSE)
  214.   {
  215.     printf("(depth=%d, pick=%d, onoff=%d)", i->Depth,
  216.                                             i->PlanePick,
  217.                                             i->PlaneOnOff);
  218.     fflush(stdout);
  219.   }
  220.  
  221.   /*
  222.       PRESCAN:  Examine dmax planes of i and compute
  223.  
  224.         D   = the real depth (without trailing 0 planes)
  225.         pp  = the new PlanePick value
  226.         p10 = the new PlaneOnOff value
  227.   */
  228.  
  229.   dmax= (0 < planes && planes < i->Depth) ? planes : i->Depth;
  230.  
  231.   for(d= D= 0; d<dmax; d++)
  232.   {
  233.     /* check if we have some image data for plane d */
  234.     if(i->PlanePick & (1<<d))
  235.     {
  236.       UWORD n, *p, v;
  237.  
  238.       /* scan the image data of plane d */
  239.       for(n=0, p=idata, v=*p; n < p16; n++, p++)
  240.         if(*p != v)
  241.           break;
  242.  
  243.       if(n==p16 && v==0xFFFF) /* plane d is entirely 1 */
  244.         p10 |= (1<<d);  /* pp bit is already 0 */
  245.  
  246.       if( n!=p16 || (n==p16 && v!=0x0000 && v!=0xFFFF) )
  247.         pp |= (1<<d);
  248.  
  249.       if( n!=p16 || (n==p16 && v!=0x0000) )
  250.         D= d;
  251.  
  252.       idata= &idata[p16];
  253.     }
  254.     else if(i->PlaneOnOff & (1<<d))
  255.     {
  256.       p10 |= (1<<d);
  257.       D=d;
  258.     }
  259.   }
  260.  
  261.   ++D;
  262.  
  263.   if( (optimode & OPT_VERBOSE) && (D != dmax || pp != i->PlanePick || p10 != i->PlaneOnOff) )
  264.   {
  265.     printf(" -> (%d,%d,%d)", D,pp,p10);
  266.     fflush(stdout);
  267.   }
  268.  
  269.   /* compute the #of planes in the output image */
  270.   P= ( planes>D && !(optimode & OPT_NOEXPAND) ) ? planes : D;
  271.  
  272.   if(P != i->Depth || pp != i->PlanePick || p10 != i->PlaneOnOff)
  273.   {
  274.     UWORD p8= p16 * sizeof(UWORD);
  275.     UWORD *odata;
  276.     ULONG osize= P * p8;
  277.  
  278.     if( o= (struct Image *)AllocMem(sizeof(struct Image),MEMF_CLEAR) )
  279.     {
  280.       if( odata= (UWORD *)AllocMem(osize,TypeOfMem(i->ImageData)|MEMF_CLEAR) )
  281.       {
  282.         CopyMem( (APTR)i, (APTR)o, sizeof(struct Image) );
  283.         o->ImageData= odata;
  284.  
  285.         idata= i->ImageData;
  286.  
  287.         for(d=0; d<D; d++)
  288.         {
  289.           if( pp & (1<<d) )
  290.           {
  291.             if(i->PlanePick & (1<<d))
  292.             {
  293.               CopyMem( (APTR)idata, (APTR)odata, p8 );
  294.               idata= &idata[p16];
  295.               odata= &odata[p16];
  296.             }
  297.             else /* !PlanePick bit (should not happen) */
  298.             {
  299.               memset( (char *)odata, (i->PlaneOnOff & (1<<d)) ? 0xFF : 0x00, p8 );
  300.               odata= &odata[p16];
  301.             }
  302.           }
  303.           else /* !pp bit */
  304.           {
  305.             if(i->PlanePick & (1<<d))
  306.               idata= &idata[p16];
  307.  
  308.             if( !(optimode & OPT_CRITICAL) )
  309.             {
  310.               memset( (char *)odata, (p10 & (1<<d)) ? 0xFF : 0x00, p8 );
  311.               odata= &odata[p16];
  312.               pp |= (1<<d);
  313.               p10 &= ~(1<<d);
  314.             }
  315.           }
  316.         }
  317.  
  318.         if(D>=3 && D<P) /* no need to check OPT_NOEXPAND sice P is < D if set */
  319.         {
  320.           UWORD *p;
  321.  
  322.           if( p= (UWORD *)malloc(p8) )
  323.           {
  324.  
  325.             if( (optimode & OPT_REMAPV37) && p10<=7 )
  326.             {
  327.               /*
  328.                   REMAP:  Make colors 4-7 become the last 4 in the palette
  329.  
  330.                   Algo: (1) OR together all planes > 2,
  331.                         (2) invert the result,
  332.                         (3) AND it with plane 2 and
  333.                         (4) OR the result with all planes > 2
  334.  
  335.                   Note: There is no need to expand the image data if p10 &~ %111 != 0
  336.               */
  337.  
  338.               /* move to plane 2 */
  339.  
  340.               idata= i->ImageData;
  341.  
  342.               for(d=0; d<2; d++)
  343.                 if(i->PlanePick & (1<<d))
  344.                   idata= &idata[p16];
  345.  
  346.               if(i->PlanePick & (1<<2))
  347.               {
  348.                 memcpy((char *)p, (char *)idata, p8);
  349.                 idata= &idata[p16];
  350.               }
  351.               else memset( (char *)p, (p10 & (1L<<2)) ? 0xFF : 0x00, p8 );
  352.  
  353.               /* or planes 3..D, invert them, AND the result with plane 2 */
  354.  
  355.               for(d=3; d<D; d++)
  356.               {
  357.                 if(i->PlanePick & (1<<d))
  358.                 {
  359.                   memandnot( (char *)p, (char *)idata, p8 );
  360.                   idata= &idata[p16];
  361.                 }
  362.                 /* else bit d of i->PlaneOnOff is 0 --> no-op */
  363.               }
  364.  
  365.               /* move to plane 3 */
  366.  
  367.               odata= o->ImageData;
  368.  
  369.               for(d=0; d<3; d++)
  370.                 if(pp & (1<<d))
  371.                   odata= &odata[p16];
  372.  
  373.               for(d=3; d<P; d++)
  374.               {
  375.                 if( d>=D || pp & (1<<d) )
  376.                 {
  377.                   memor( (char *)odata, (char *)p, p8 );
  378.                   odata= &odata[p16];
  379.                   pp |= (1<<d);
  380.                 }
  381.               }
  382.             }
  383.  
  384.             else /* !REMAPV37 */
  385.             {
  386.               /*
  387.                   EXPAND:  Remap the last 4 colors of i to the last 4 colors of o
  388.  
  389.                   Algo: (1) OR together all planes but the last
  390.                         (2) AND the result with the last plane
  391.                         (3) set the result in all new planes
  392.  
  393.                   Note: if any plane of i but the last is entirely 1 then we can
  394.                         simply copy the last plane of i to all new planes in o
  395.               */
  396.  
  397.               idata= i->ImageData;
  398.  
  399.               if( p10 &~ (1<<(D-1)) == 0)
  400.               {
  401.                 memset( (char *)p, 0x00, p8 );
  402.  
  403.                 for(d=0; d<D-1; d++)
  404.                 {
  405.                   if(i->PlanePick & (1<<d))
  406.                   {
  407.                     memor( (char *)p, (char *)idata, p8 );
  408.                     idata= &idata[p16];
  409.                   }
  410.                 }
  411.                 /* else plane d is entirely 0 */
  412.  
  413.                 if( i->PlanePick & (1<<(D-1)) )
  414.                   memand( (char *)p, (char *)idata, p8 );
  415.                 /* else the last plane is entirely 1 */
  416.               }
  417.               else /* move to the last plane */
  418.               {
  419.                 for(d=0; d<D-1; d++)
  420.                   if(i->PlanePick & (1<<d))
  421.                     idata= &idata[p16];
  422.  
  423.                 if( i->PlanePick & (1<<(D-1)) )
  424.                   memcpy( (char *)p, (char *)idata, p8 );
  425.                 else
  426.                   memset( (char *)p, 0xFF, p8 );
  427.               }
  428.  
  429.               /* move to plane D */
  430.  
  431.               odata= o->ImageData;
  432.  
  433.               for(d=0; d<D; d++)
  434.                 if(pp & (1<<d))
  435.                   odata= &odata[p16];
  436.  
  437.               for(d=D; d<P; d++)
  438.               {
  439.                 memcpy( (char *)odata, (char *)p, p8 );
  440.                 odata= &odata[p16];
  441.                 pp |= (1<<d);
  442.               }
  443.  
  444.             }
  445.  
  446.             free(p);
  447.           }
  448.           else /* !p --> panic! */
  449.           {
  450.             FreeMem(o->ImageData,osize);
  451.             FreeMem(o,sizeof(struct Image));
  452.             o= (struct Image *)0L;
  453.           }
  454.         }
  455.  
  456.         o->Depth= P;
  457.         o->PlanePick= pp;
  458.         o->PlaneOnOff= p10;
  459.  
  460.       }
  461.       else /* !odata */
  462.       {
  463.         FreeMem(o,sizeof(struct Image));
  464.         o= (struct Image *)0L;
  465.       }
  466.     }
  467.   }
  468.  
  469.   if(optimode & OPT_VERBOSE)
  470.   {
  471.     if(o && o!=i)
  472.       printf(" -> (%d,%d,%d)", o->Depth, o->PlanePick, o->PlaneOnOff);
  473.     putchar('\n');
  474.   }
  475.  
  476.   return o;
  477. }
  478.  
  479.  
  480. int main(int argc, char **argv)
  481. {
  482.   struct RDArgs *a;
  483.   LONG args[6] = { 0,0,0,0,0,0 };
  484.  
  485.   WORD numplanes= 0;
  486.   char *whoami= *argv;
  487.   int rc= RETURN_OK;
  488.  
  489.   if( a= ReadArgs("NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,CRITICAL/S,REMAPV37/S,VERBOSE/S", args, NULL) )
  490.   {
  491.     char **flist= (char **)args[0];
  492.  
  493.     if(args[1])
  494.     {
  495.       if( (numplanes= (WORD)*(LONG *)(args[1])) < 1 )
  496.       {
  497.         fprintf(stderr,"%s: Illegal maximum depth %d\n",whoami,numplanes);
  498.         rc= RETURN_FAIL;
  499.       }
  500.     }
  501.  
  502.     if(flist && rc == RETURN_OK)
  503.     {
  504.       if( IconBase= (struct IconBase *)OpenLibrary(ICONNAME,36) )
  505.       {
  506.         while(*flist && rc == RETURN_OK)
  507.         {
  508.           char *iname= (char *)malloc( strlen(*flist) + 1 );
  509.  
  510.           if(iname)
  511.           {
  512.             struct DiskObject *icon;
  513.             strcpy(iname, *flist);
  514.  
  515.             if( (icon= GetDiskObject(iname)) == NULL )
  516.             {
  517.               int x= strlen(iname) - 5;
  518.               if(x>0 && !stricmp(&(iname[x]),".info"))
  519.               {
  520.                 iname[x]= '\0';
  521.                 icon= GetDiskObject(iname);
  522.               }
  523.             }
  524.  
  525.             if(icon)
  526.             {
  527.               struct Gadget *g= &icon->do_Gadget;
  528.  
  529.               struct Image *ogr, *osr;
  530.               int modified= 0;
  531.               int flags= 0;
  532.  
  533.               ogr= osr= (struct Image *)0L;
  534.  
  535.               if(args[2]) flags |= OPT_NOEXPAND;
  536.               if(args[3]) flags |= OPT_CRITICAL;
  537.               if(args[4]) flags |= OPT_REMAPV37;
  538.               if(args[5]) flags |= OPT_VERBOSE;
  539.  
  540.               if(g->GadgetRender && (g->Flags & GFLG_GADGIMAGE))
  541.               {
  542.                 struct Image *i= (struct Image *)g->GadgetRender;
  543.  
  544.                 if(flags & OPT_VERBOSE)
  545.                   printf("Normal   ");
  546.  
  547.                 if( ogr= optimize_image(i,numplanes,flags) )
  548.                 {
  549.                   if(ogr != i)
  550.                   {
  551.                     g->GadgetRender= (APTR)ogr;
  552.                     ++modified;
  553.                   }
  554.                   else ogr= (struct Image *)0L; /* don't free ogr */
  555.  
  556.                   if(g->SelectRender && (g->Flags & GFLG_GADGHIMAGE))
  557.                   {
  558.                     i= (struct Image *)g->SelectRender;
  559.  
  560.                     if(flags & OPT_VERBOSE)
  561.                       printf("Selected ");
  562.  
  563.                     if( osr= optimize_image(i,numplanes, flags) )
  564.                     {
  565.                       if(osr != i)
  566.                       {
  567.                         g->SelectRender= (APTR)osr;
  568.                         ++modified;
  569.                       }
  570.                       else osr= (struct Image *)0L; /* don't free osr */
  571.                     }
  572.                     else
  573.                     {
  574.                       fprintf(stderr,"%s: %s.info: not enough free memory to optimize the selected image\n",whoami,iname);
  575.                       rc= RETURN_ERROR;
  576.                     }
  577.                   }
  578.                 }
  579.                 else
  580.                 {
  581.                   fprintf(stderr,"%s: %s.info: not enough free memory to optimize the normal image\n",whoami,iname);
  582.                   rc= RETURN_ERROR;
  583.                 }
  584.               }
  585.  
  586.               if( modified && rc == RETURN_OK )
  587.               {
  588.                 if( !PutDiskObject(iname,icon) )
  589.                   PrintFault(rc= IoErr(), iname);
  590.               }
  591.  
  592.               if(ogr) ogr= free_image(ogr);
  593.               if(osr) osr= free_image(osr);
  594.  
  595.               FreeDiskObject(icon);
  596.             }
  597.             else /* !icon */
  598.             {
  599.               fprintf(stderr,"%s: GetDiskObject() failed for %s[.info]\n",whoami,iname);
  600.               rc= IoErr();
  601.             }
  602.  
  603.             free(iname);
  604.           }
  605.           else /* !iname */
  606.           {
  607.             fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
  608.             rc= RETURN_ERROR;
  609.           }
  610.  
  611.           ++flist;
  612.         }
  613.         CloseLibrary((struct Library *)IconBase);
  614.       }
  615.       else
  616.       {
  617.         fprintf(stderr,"%s: You need %s V36+",whoami,ICONNAME);
  618.         rc= RETURN_ERROR;
  619.       }
  620.     }
  621.     FreeArgs(a);
  622.   }
  623.   else /* !ReadArgs */
  624.   {
  625.     if(argc == 1)
  626.       display_version_information();
  627.     else
  628.       PrintFault(IoErr(), NULL);
  629.   }
  630.  
  631.   exit(rc);
  632. }
  633.